﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.Contracts;
using IWMAG.Core.EnhancedProperties.PropertyNodes;
using IWMAG.Core.EnhancedProperties.Extensions;

namespace IWMAG.Core.EnhancedProperties.Advanced
{
    public static class AdvancedPropertyExtensions
    {
        public static int AddConstantValue<T>(this IPropertyContainer owner, PropertyBacker<T> backer, T val)
        {
            Contract.Requires(owner != null);
            Contract.Requires(backer != null);

            if (!backer.Metadata.CanSetValue)
            {
                throw new NotSupportedException("Property does not support sets.");
            }

            var actual = backer.GetOrCreatePropertyNodeList(owner);
            var highest = actual.GetHighestPriority() + 1;

            actual.AddOrModifyListMember(highest, i => new SetNode<T>(i, val), node =>
            {
                node.SetNodeValue(val);
                return true;
            });

            PropertyManager.RegisterPropertyAffected(owner.UniqueID, backer.UniqueID);
            return highest;
        }

        public static bool ClearValue<T>(this IPropertyContainer owner, PropertyBacker<T> backer, int priority)
        {
            Contract.Requires(owner != null);
            Contract.Requires(backer != null);

            if (!backer.Metadata.CanSetValue)
            {
                throw new NotSupportedException("Property does not support sets, and by extension, clears.");
            }

            PropertyNodeList<T> t;
            if (backer.BackingDictionary.TryGetValue(owner.UniqueID, out t))
            {
                var removed = t.RemoveListMember(priority);
                if (!removed)
                {
                    return false;
                }

                if (!backer.Metadata.IsFrequentAccess && t.IsEmptyList())
                {
                    backer.BackingDictionary.Remove(owner.UniqueID);
                    t.Dispose();
                    t = null;
                }

                return true;
            }
            else
            {
                return false;
            }
        }

        public static TryPropertyBacker Try(this IPropertyContainer container)
        {
            return new TryPropertyBacker(container);
        }

        
    }
}
